package com.common.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.util.StopWatch;

import lombok.extern.slf4j.Slf4j;

/**
 * @author ficus
 * 获取日志方法
 */
@Slf4j
abstract class LogAspect {
	
	@Value("${pmafs.timeout:2000}")
	private int timeout;
	
	protected Object around(ProceedingJoinPoint point) throws Throwable {
		Object result = null;
		String descInfo = getDescInfo(point);
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		log.debug("进入{}调用,入参{}",descInfo,getCalledMethodParam(point));
		try {
			result = point.proceed();
		} catch (Throwable e) {
			log.error("调用{}出现异常,异常信息{}",descInfo,e);
			throw e;
		}
		log.debug("完成{}调用，出参{}",descInfo,result);
		stopWatch.stop();
		long consumeTime = stopWatch.getTotalTimeMillis();
		log.debug("完成{}调用,一共耗时{}毫秒",descInfo,consumeTime);
		if(consumeTime>timeout) {
			log.warn("完成{}调用,一共耗时{}毫秒",descInfo,consumeTime);
		}
		return result;
	}
	
	
	/**
	 * 获取注解上的描述信息.
	 * @param joinPoint
	 * @return
	 */
	protected String getDescInfo (ProceedingJoinPoint joinPoint) {
		return getCalledMethodFullName(joinPoint);
	}

	/**
	 * 获取被调用方法的全名（类名+方法名）
	 * @param joinPoint
	 * @return
	 */
	private String getCalledMethodFullName (ProceedingJoinPoint joinPoint){
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		String className = joinPoint.getTarget().getClass().getName();
		String methodName = signature.getName();
		StringBuilder stringBuilder = new StringBuilder("");
		stringBuilder.append(className).append(".").append(methodName).append("()");
		return  stringBuilder.toString();
	}

	/**
	 * 获取被调用方法入参.
	 * @param joinPoint
	 * @return
	 */
	protected String getCalledMethodParam(ProceedingJoinPoint joinPoint){
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		Object[] args = joinPoint.getArgs();
		LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
		String[] paramNames = u.getParameterNames(method);
		if (args != null && args.length >0 && paramNames != null) {
			StringBuilder params = new StringBuilder();
			for (int i = 0; i < args.length; i++) {
				params.append(" ").append(paramNames[i]).append(": ").append(args[i]);
			}
			return params.toString();
		}
		return "[]";
	}
}
